_require "../../../../basis.smi"
_require "../../../../smlformat-lib.smi"
_require "../../../data/symbols/main/Loc.smi"
_require "../../../data/symbols/main/Symbol.smi"
_require "../../../data/symbols/main/RecordLabel.smi"
_require "../../../data/name/main/CodeLabel.smi"
_require "../../../data/types/main/Types.ppg.smi"
_require "../../../data/types/main/DynamicKind.ppg.smi"
_require "../../../data/runtimetypes/main/FFIAttributes.ppg.smi"
_require "../../../data/builtin/main/BuiltinPrimitive.ppg.smi"
_require "../../../compilerIRs/typedlambda/main/TypedLambda.ppg.smi"
_require local "../../../compilerIRs/absyn/main/ConstFormat.smi"

structure RecordCalc =
struct

  type loc = Loc.loc
  type ty = Types.ty
  type btvEnv = Types.btvEnv
  type varInfo = TypedLambda.varInfo
  type exVarInfo = Types.exVarInfo
  datatype cast = datatype BuiltinPrimitive.cast
  datatype tlint = datatype TypedLambda.tlint
  datatype tlconst = datatype TypedLambda.tlconst
  datatype rcconst =
      INT of tlint
    | CONST of tlconst
    | SIZE of DynamicKind.size' * ty
    | TAG of DynamicKind.tag' * ty
  datatype tlstring = datatype TypedLambda.tlstring
  datatype rcvalue =
      RCCONSTANT of rcconst
    | RCVAR of varInfo
  datatype rcexp =
      RCVALUE of rcvalue * loc
    | RCSTRING of tlstring * loc
    | RCEXVAR of exVarInfo * loc
    | RCFNM of
      {
        argVarList : varInfo list,
        bodyTy : ty,
        bodyExp : rcexp,
        loc : loc
      }
    | RCAPPM of
      {
        funExp : rcexp,
        funTy : ty,
        argExpList : rcexp list,
        loc : loc
      }
    | RCSWITCH of
      {
        exp : rcexp,
        expTy : ty,
        branches : {const : tlint, body : rcexp} list,
        defaultExp : rcexp,
        resultTy : ty,
        loc : loc
      }
    | RCPRIMAPPLY of
      {
        primOp : TypedLambda.primInfo,
        instTyList : ty list,
        instSizeList : rcvalue list,
        instTagList : rcvalue list,
        argExpList : rcexp list,
        loc : loc
      }
    | RCRECORD of
      {
        fields : {exp : rcexp, ty : ty, size : rcvalue, tag : rcvalue}
                   RecordLabel.Map.map,
        loc : loc
      }
    | RCSELECT of
      {
        label : RecordLabel.label,
        indexExp : rcexp,
        recordExp : rcexp,
        recordTy : ty,
        resultTy : ty,
        resultSize : rcvalue,
        resultTag : rcvalue,
        loc : loc
      }
    | RCMODIFY of
      {
        label : RecordLabel.label,
        indexExp : rcexp,
        recordExp : rcexp,
        recordTy : ty,
        elementExp : rcexp,
        elementTy : ty,
        elementSize : rcvalue,
        elementTag : rcvalue,
        loc : loc
      }
    | RCLET of
      {
        decl : rcdecl,
        body : rcexp,
        loc : loc
      }
    | RCRAISE of
      {
        exp : rcexp,
        resultTy : ty,
        loc : loc
      }
    | RCHANDLE of
      {
        exp : rcexp,
        exnVar : varInfo,
        handler : rcexp,
        resultTy : ty,
        loc : loc
      }
    | RCTHROW of
      {
        catchLabel : FunLocalLabel.id,
        argExpList : rcexp list,
        resultTy : ty,
        loc : loc
      }
    | RCCATCH of
      {
        catchLabel : FunLocalLabel.id,
        argVarList : varInfo list,
        catchExp : rcexp,
        tryExp : rcexp,
        resultTy : ty,
        loc : loc
      }
    | RCPOLY of
      {
        btvEnv : btvEnv,
        constraints : Types.constraint list,
        expTyWithoutTAbs : ty,
        exp : rcexp,
        loc : loc
      }
    | RCTAPP of
      {
        exp : rcexp,
        expTy : ty,
        instTyList : ty list,
        loc : loc
      }
    | RCFOREIGNAPPLY of
      {
        funExp : rcexp,
        argExpList : rcexp list,
        attributes : FFIAttributes.attributes,
        resultTy : ty option,
        loc : loc
      }
    | RCCALLBACKFN of
      {
        attributes : FFIAttributes.attributes,
        argVarList : varInfo list,
        bodyExp : rcexp,
        resultTy : ty option,
        loc : loc
      }
    | RCCAST of
      {
        exp : rcexp,
        expTy : ty,
        targetTy : ty,
        cast : cast,
        loc : loc
      }
    | RCINDEXOF of
      {
        fields : {ty : ty, size : rcvalue} RecordLabel.Map.map,
        label : RecordLabel.label,
        loc : loc
      }
  and rcdecl =
      RCVAL of
      {
        var : varInfo,
        exp : rcexp,
        loc : loc
      }
    | RCVALREC of {var : varInfo, exp : rcexp} list * loc
    | RCEXPORTVAR of
      {
        weak : bool,
        var : exVarInfo,
        exp : rcexp
      }
    | RCEXTERNVAR of exVarInfo * Types.provider

  val format_rcconst : rcconst -> SMLFormat.format
  val formatWithType_rcconst : rcconst -> SMLFormat.format
  val format_rcexp : rcexp -> SMLFormat.format
  val formatWithType_rcexp : rcexp -> SMLFormat.format
  val format_rcdecl : rcdecl -> SMLFormat.format
  val formatWithType_rcdecl : rcdecl -> SMLFormat.format

end
